gdk/wayland: Break only implicit grabs on wl_pointer.leave w/ pressed buttons
authorCarlos Garnacho <carlosg@gnome.org>
Thu, 3 Jun 2021 14:18:28 +0000 (16:18 +0200)
committerCarlos Garnacho <carlosg@gnome.org>
Thu, 3 Jun 2021 15:13:12 +0000 (17:13 +0200)
The releasing of grabs while a button is pressed (e.g. after starting dnd, or
dragging the window, or going to overview with a pressed button, etc...) was
generalized here in https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/1879.

However we shouldn't break all grabs here. In the case of grabbing popups,
compositors will still emit crossing events between client surfaces (e.g.
popping up and selecting a menu item via press-drag-release), breaking all
grabs here means inconsistent client state, that was
https://gitlab.gnome.org/GNOME/gtk/-/issues/2746.

That was fixed in mutter, by essentially making implicit grabs
owner_events=FALSE, however that breaks the mentioned use pattern entirely.
Mutter is changing this behavior back, so GTK should handle these crossing
events.

The grab that we are interested in breaking here is the implicit pointer
one. Popups will be dismissed via other means if the compositor says their
active grab needs breaking. This still leaves dnd/move/resize drags in
one place, while not allowing #2746 to happen with popups.

gdk/wayland/gdkdevice-wayland.c

index 3b9c1e02daca02fc075cb372d0a74f717db1a115..ca94a6e7e5e13e702aa90e332e279e639686d342 100644 (file)
@@ -1550,6 +1550,7 @@ pointer_handle_leave (void              *data,
   GdkWaylandSeat *seat = data;
   GdkEvent *event;
   GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (seat->display);
+  GdkDeviceGrabInfo *grab;
 
   if (!surface)
     return;
@@ -1561,8 +1562,11 @@ pointer_handle_leave (void              *data,
     return;
 
   _gdk_wayland_display_update_serial (display_wayland, serial);
+  grab = _gdk_display_get_last_device_grab (seat->display,
+                                            seat->logical_pointer);
 
-  if (seat->pointer_info.button_modifiers != 0)
+  if (seat->pointer_info.button_modifiers != 0 &&
+      grab && grab->implicit)
     {
       gulong display_serial;